<script setup lang="ts">
import { onMounted, ref } from 'vue'
import * as echarts from 'echarts/core'
import 'echarts-wordcloud'
import { BarChart, LineChart, MapChart } from 'echarts/charts'
import {
  TitleComponent,
  TooltipComponent,
  GridComponent,
  // 数据集组件
  DatasetComponent,
  // 内置数据转换器组件 (filter, sort)
  TransformComponent
} from 'echarts/components'
import { LabelLayout, UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
import type {
  // 系列类型的定义后缀都为 SeriesOption
  BarSeriesOption,
  LineSeriesOption
} from 'echarts/charts'
import type {
  // 组件类型的定义后缀都为 ComponentOption
  TitleComponentOption,
  TooltipComponentOption,
  GridComponentOption,
  DatasetComponentOption
} from 'echarts/components'
import type { ComposeOption } from 'echarts/core'
import axios from 'axios'
import { WordCloudSeriesOption } from 'echarts'

// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
type ECOption = ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | DatasetComponentOption
  | WordCloudSeriesOption
>

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  BarChart,
  LineChart,
  MapChart,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer
])

interface ChartData {
  name: string
  value: number
}

onMounted(() => {
  init()
})

const main = ref()
const sub = ref()
const basic = ref()

const mainData = ref<ChartData[]>([])
const subData = ref<ChartData[]>([])
const basicData = ref<ChartData[]>([])

const init = () => {
  // 基于准备好的dom，初始化echarts实例
  const mainChart = echarts.init(main.value, 'dark')
  const subChart = echarts.init(sub.value, 'dark')
  const basicChart = echarts.init(basic.value, 'dark')

  // 获取数据绘制图表
  axios.get('/api/attraction/getMainData').then((res) => {
    const { code, data } = res.data
    if (code === 200) {
      mainData.value = data
      const mainOption: ECOption = {
        grid: {
          top: '20%',
          left: '10%', // grid布局设置适当调整避免X轴文字只能部分显示
          right: '5%', // grid布局设置适当调整避免X轴文字只能部分显示
          bottom: '25%'
        },
        title: {
          text: '按主类分组统计数量',
          textStyle: {
            color: '#fee242'
          }
        },
        tooltip: {},
        xAxis: {
          data: mainData.value.map((main) => main.name),
          axisLabel: {
            interval: 0, // 坐标轴刻度标签的显示间隔，在类目轴中有效；默认会采用标签不重叠的策略间隔显示标签；可以设置成0强制显示所有标签；如果设置为1，表示『隔一个标签显示一个标签』，如果值为2，表示隔两个标签显示一个标签，以此类推。
            rotate: -45, // 刻度标签旋转的角度，在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠；旋转的角度从-90度到90度
            inside: false, // 刻度标签是否朝内，默认朝外
            margin: 5 // 刻度标签与轴线之间的距离
          }
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            name: '景点数量',
            type: 'bar',
            data: mainData.value.map((main) => main.value)
          }
        ]
      }
      mainChart.setOption(mainOption)
    }
  })
  axios.get('/api/attraction/getSubData').then((res) => {
    const { code, data } = res.data
    if (code === 200) {
      subData.value = data
      const subOption: ECOption = {
        grid: {
          top: '20%',
          left: '5%', // grid布局设置适当调整避免X轴文字只能部分显示
          right: '5%', // grid布局设置适当调整避免X轴文字只能部分显示
          bottom: '30%'
        },
        title: {
          text: '按亚类分组统计数量',
          textStyle: {
            color: '#fee242'
          }
        },
        tooltip: {},
        xAxis: {
          data: subData.value.map((sub) => sub.name),
          axisLabel: {
            interval: 0, // 坐标轴刻度标签的显示间隔，在类目轴中有效；默认会采用标签不重叠的策略间隔显示标签；可以设置成0强制显示所有标签；如果设置为1，表示『隔一个标签显示一个标签』，如果值为2，表示隔两个标签显示一个标签，以此类推。
            rotate: -45, // 刻度标签旋转的角度，在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠；旋转的角度从-90度到90度
            inside: false, // 刻度标签是否朝内，默认朝外
            margin: 5 // 刻度标签与轴线之间的距离
          }
        },
        yAxis: {},
        series: [
          {
            name: '景点数量',
            type: 'line',
            data: subData.value.map((sub) => sub.value)
          }
        ]
      }
      subChart.setOption(subOption)
    }
  })
  axios.get('/api/attraction/getBasicData').then((res) => {
    const { code, data } = res.data
    if (code === 200) {
      basicData.value = data
      const basicOption: ECOption = {
        tooltip: { show: true },
        series: [
          {
            type: 'wordCloud',
            // 要绘制云的形状,默认是 circle, 可选的参数有 cardioid 、 diamond 、 triangle-forward 、 triangle 、 star
            shape: 'circle',
            // 数据中的值将映射到的文本大小范围。
            // 默认值为最小12px，最大60px。
            sizeRange: [12, 30],
            // 文字旋转范围和步进程度。文本将通过rotationStep 45在[- 90,90]范围内随机旋转
            rotationRange: [-90, 90],
            rotationStep: 45,
            // 网格大小(以像素为单位)，用于标记画布的可用性
            // 网格大小越大，单词之间的间隔就越大
            gridSize: 8,
            // 设置为true允许文字部分地绘制在画布之外。
            // 允许画比画布大的字
            // 从echarts-wordcloud@2.1.0开始支持该选项
            drawOutOfBound: false,
            // 是否执行布局动画。
            //当单词较多时禁用会导致UI阻塞。
            layoutAnimation: true,

            // 全局文本样式
            textStyle: {
              fontFamily: 'sans-serif',
              fontWeight: 'bold',
              // Color可以是回调函数或颜色字符串
              color: function () {
                // 任意颜色
                return (
                  'rgb(' +
                  [
                    Math.round(Math.random() * 160),
                    Math.round(Math.random() * 160),
                    Math.round(Math.random() * 160)
                  ].join(',') +
                  ')'
                )
              }
            },
            emphasis: {
              focus: 'self',
              textStyle: {
                textShadowBlur: 10,
                textShadowColor: '#333'
              }
            },
            data: basicData.value
          }
        ]
      }
      basicChart.setOption(basicOption)
    }
  })
  window.addEventListener('resize', function () {
    mainChart.resize()
    subChart.resize()
    basicChart.resize()
  })
}
</script>

<template>
  <div class="main">
    <div ref="main" style="height: 45vmin; width: 30vmax"></div>
    <div ref="sub" style="height: 45vmin; width: 60vmax"></div>
    <div ref="basic" style="height: 45vmin; width: 90vmax"></div>
  </div>
</template>

<style scoped>
.main {
  width: 100vmax;
  height: 100vmin;
  background-color: rgb(0, 47, 149);
  display: flex;
  justify-content: space-around;
  flex-wrap: wrap;
  align-items: center;
}
</style>
